/*
 * Galaxium Messenger
 * 
 * Copyright (C) 2008 Philippe Durand <draekz@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

using Galaxium.Core;

using Anculus.Core;

namespace Galaxium.Protocol
{
	public class TunnelSocket
	{
		private TunnelSocket ()
		{
			
		}
		
		public static Socket ConnectToHttpsProxy (string proxyAdress, ushort proxyPort, string destAddress, ushort destPort, string userName, string password)
		{
			IPAddress destIP = null;
			IPAddress proxyIP = null;
			
			Log.Debug ("Getting proxy IP");
			try
			{
				proxyIP =  IPAddress.Parse (proxyAdress);
			}
			catch (FormatException)
			{
				
				proxyIP = Dns.GetHostByName (proxyAdress).AddressList[0];
			}
			
			Log.Debug ("Getting dest IP");
			try
			{
				destIP = IPAddress.Parse (destAddress);
			}
			catch (FormatException)
			{
				//destIP = Dns.GetHostByName (destAddress).AddressList[0];
			}
			
			Log.Debug ("Connecting to proxy server {0}:{1}", proxyIP, proxyPort);
			
			IPEndPoint proxyEndPoint = new IPEndPoint (proxyIP, proxyPort);
			
			Socket tunnelSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
			
			try
			{
				tunnelSocket.Connect (proxyEndPoint);
			}
			catch (SocketException ex)
			{
				throw new ProxyConnectionException ("Proxy: "+ex.Message);
			}
			
			string connectString = "CONNECT "+destAddress+":"+destPort.ToString ()+" HTTP/1.0\n";
			
			if (!string.IsNullOrEmpty (userName) && !string.IsNullOrEmpty(password))
			{
				Log.Debug ("PROXY: Using basic authentication: {1}:{2}", userName, password);
				
				// We do have a username/password, lets try and use them.
				string auth = Convert.ToBase64String (Encoding.ASCII.GetBytes (string.Format ("{1}:{2}", userName, password)));
				connectString += "Proxy-authorization: basic "+auth;
			}
			
			// We must finish off with the newline to tell the server our request is done.
			connectString = connectString + "\n";
			
			byte[] connectBytes = Encoding.ASCII.GetBytes (connectString);
			
			int connectSent = tunnelSocket.Send (connectBytes, connectBytes.Length, SocketFlags.None);
			
			if (connectSent != connectBytes.Length)
				throw new ProxyConnectionException ("Proxy: Unable to auth");
			
			byte[] receivedBytes = new byte[255];
			
			// Receive the whole response.
			
			int receivedSize = tunnelSocket.Receive (receivedBytes, 255, SocketFlags.None);
			string connectResponse = Encoding.ASCII.GetString (receivedBytes, 0, receivedSize);
			
			if (!connectResponse.Contains ("HTTP/1.0 200"))
			{
				// Invalid Response, we are NOT connected.
				throw new ProxyConnectionException ("Proxy: Request rejected.");
			}
			
			Console.WriteLine ("PROXY: Successfully connected through proxy connection!");
			
			return tunnelSocket;
		}
	}
}